package com.syqc.maps.clusters

import android.content.Context
import android.graphics.Color
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.os.Message
import android.util.TypedValue
import android.view.Gravity
import android.widget.TextView
import android.util.LruCache
import com.amap.api.maps.AMap
import com.amap.api.maps.AMap.OnCameraChangeListener
import com.amap.api.maps.AMap.OnMarkerClickListener
import com.amap.api.maps.AMapUtils
import com.amap.api.maps.model.*
import com.syqc.maps.utils.MarkerSet
import com.syqc.comlib.utils.MLog
import com.syqc.monitor.R


class ClusterOverlay(
    private val context: Context, private val aMap: AMap
) : OnCameraChangeListener, OnMarkerClickListener {
    private val mClusterItems = mutableListOf<ClusterItem>()
    private val mClusters = mutableListOf<Cluster>()
    private val mMarkers = mutableListOf<Marker>()
    private var mClusterRender: ClusterRender? = null
    private var mClusterListener: ClusterListener? = null
    private var mLruCache: LruCache<Int, BitmapDescriptor>? = null

    //marker 线程
    private val mMarkerThread = HandlerThread("AddMarker")
    private var mMarkerHandler: MarkerHandler? = null

    //计算聚合线程
    private val mClusterThread = HandlerThread("CalculateCluster")
    private var mClusterHandler: ClusterHandler? = null

    //聚合距离
    private var mClusterDistance: Double = 0.0

    //最小聚合数
    private var mClusterSize: Int = dp2px(context, 80f)

    //是否已取消
    private var isCanceled = false

    //像素比例
    private var mPXMeter = 0f

    //车辆ID
    private var carId = ""

    //是否显示速度
    private var isShowSpeed = false

    init {
        mLruCache = object : LruCache<Int, BitmapDescriptor>(100) {
            override fun entryRemoved(
                evicted: Boolean, key: Int,
                oldValue: BitmapDescriptor?,
                newValue: BitmapDescriptor?
            ) {
                oldValue?.recycle()
            }
        }
        isShowSpeed = MarkerSet.mMarkerSet.showSpeed
        mPXMeter = aMap.scalePerPixel
        mClusterDistance = (mClusterSize * mPXMeter).toDouble()
        aMap.setOnMarkerClickListener(this)
        aMap.setOnCameraChangeListener(this)
        initThread()
    }

    /**
     * 添加聚合点数据
     *
     * @param items
     * @param carId
     */
    fun addClusterItems(items: MutableList<ClusterItem>?, carId: String) {
        this.carId = carId
        isCanceled = true
        clearMarkers()
        clearClusters()
        if (items !== null)
            mClusterItems.addAll(items)

        val item = removeClusterItem(carId)
        if (item != null) mClusterItems.add(item)
        assignClusters()
    }

    /**
     * 添加一个聚合点
     *
     * @param item
     */
    fun addClusterItem(item: ClusterItem) {
        val message = Message.obtain()
        message.what = CALCULATE_SINGLE_CLUSTER
        message.obj = item
        mClusterHandler?.sendMessage(message)
    }

    /**
     * 根据车辆ID移除就数据
     */
    private fun removeClusterItem(carId: String): ClusterItem? {
        if (mClusterItems.isEmpty()) return null
        mClusterItems.forEach {
            if (carId == it.carId) {
                mClusterItems.remove(it)
                return it
            }
        }
        return null
    }

    private fun addClusterHandle(cluster: Cluster) {
        val message = Message.obtain()
        message.what = ADD_SINGLE_CLUSTER
        message.obj = cluster
        mMarkerHandler?.sendMessage(message)
    }

    private fun updateClusterHandle(cluster: Cluster) {
        val message = Message.obtain()
        message.what = UPDATE_SINGLE_CLUSTER
        message.obj = cluster
        mMarkerHandler?.removeMessages(UPDATE_SINGLE_CLUSTER)
        mMarkerHandler?.sendMessageDelayed(message, 10)
    }

    /**
     * 刷新数据
     */
    fun refresh() {
        assignClusters()
    }

    fun clearCarId() {
        this.carId = ""
    }

    /**
     * 刷新数据
     */
    fun refreshOne(carId: String) {
        this.carId = carId
        val item = removeClusterItem(carId)
        if (item != null) mClusterItems.add(item)
        assignClusters()
    }

    override fun onCameraChange(position: CameraPosition?) {}

    //地图缩放动作结束监听
    override fun onCameraChangeFinish(position: CameraPosition?) {
        mPXMeter = aMap.scalePerPixel
        mClusterDistance = (mPXMeter * mClusterSize).toDouble()
        assignClusters()
    }

    fun closeOpenCluster(isCluster: Boolean) {
        mClusterSize = if (isCluster) {
            dp2px(context, 80f)
        } else {
            0
        }
        mClusterDistance = (mPXMeter * mClusterSize).toDouble()
        assignClusters()
    }

    /**
     * Marker 点击事件处理
     * @param marker
     * @return
     */
    override fun onMarkerClick(marker: Marker?): Boolean {
        if (mClusterListener == null) return true
        val cluster = marker?.`object` as? Cluster
        if (cluster != null) {
            if (cluster.clusterCount > 1) {
                mClusterListener!!.onClusterListener(marker, cluster)
            } else {
                mClusterListener!!.onClusterItemListener(marker, cluster.clusterItems[0])
            }
            return true
        }
        return false
    }

    /**
     * 对点进行聚合
     */
    private fun assignClusters() {
        isCanceled = true
        mClusterHandler?.removeMessages(CALCULATE_CLUSTER)
        mClusterHandler?.sendEmptyMessageDelayed(CALCULATE_CLUSTER,50)
    }

    fun setClusterListener(clusterListener: ClusterListener) {
        mClusterListener = clusterListener
    }

    fun setClusterRender(clusterRender: ClusterRender) {
        mClusterRender = clusterRender
    }

    /**
     * 获取可以聚合点
     *
     * @param latLng
     * @param clusters
     * @return
     */
    private fun getCluster(latLng: LatLng, clusters: List<Cluster>): Cluster? {
        for (cluster in clusters) {
            if (cluster.isSingle) continue
            val clusterCenterPoint = cluster.latLng
            val distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint).toDouble()
            if (distance < mClusterDistance && aMap.cameraPosition.zoom < 19) {
                return cluster
            }
        }
        return null
    }

    /**
     * 更新已加入地图聚合点的样式
     *
     * @param cluster
     */
    private fun updateCluster(cluster: Cluster) {
        val marker = cluster.marker
        MLog.e("修改数据================$cluster")
        marker?.setIcon(getBitmapDesc(cluster))
    }

    /**
     * 获取聚合图标
     *
     * @param cluster
     * @return
     */
    private fun getBitmapDesc(cluster: Cluster): BitmapDescriptor {
        val num = cluster.clusterCount
        if (num > 1) {
            var bitmapDesc = mLruCache?.get(num)
            if (bitmapDesc == null) {
                bitmapDesc = BitmapDescriptorFactory.fromView(getTextView(num))
                mLruCache?.put(num, bitmapDesc)
            }
            return bitmapDesc!!
        } else {
            return if (mClusterRender != null) {
                mClusterRender!!.getBitmap(cluster.isSingle, cluster.clusterItems[0])
            } else {
                BitmapDescriptorFactory.fromResource(R.mipmap.ic_car_location_no)
            }
        }
    }

    /**
     *  获取聚合TextView
     * @param num  聚合数
     */
    private fun getTextView(num: Int): TextView {
        return TextView(context).apply {
            text = num.toString()
            gravity = Gravity.CENTER
            setTextColor(Color.WHITE)
            setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
            if (mClusterRender != null) {
                background = mClusterRender!!.getDrawable(num)
            }
        }
    }

    /**
     * 启动 计算聚合、marker处理 线程
     */
    private fun initThread() {
        mMarkerThread.start()
        mClusterThread.start()
        mMarkerHandler = MarkerHandler(mMarkerThread.looper)
        mClusterHandler = ClusterHandler(mClusterThread.looper)
    }

    /**
     * 销毁 计算聚合、marker处理 线程
     */
    private fun destroyTread() {
        mMarkerHandler?.removeCallbacksAndMessages(null)
        mClusterHandler?.removeCallbacksAndMessages(null)
        mClusterThread.quit()
        mClusterThread.quit()
    }

    /**
     * 销毁聚合数据
     */
    fun onDestroy() {
        isCanceled = true
        clearMarkers()
        clearClusters()
        mLruCache?.evictAll()
        destroyTread()
    }

    /**
     * 清除数据
     */
    fun clearData() {
        isCanceled = true
        clearMarkers()
        clearClusters()
    }

    /**
     * 清除Markers
     */
    private fun clearMarkers() {
        mMarkers.forEach {
            it.remove()
        }
        mMarkers.clear()
    }

    /**
     * 清除旧数据
     */
    private fun clearClusters() {
        mClusterItems.clear()
    }

    companion object {
        const val ADD_CLUSTERS = 0
        const val ADD_SINGLE_CLUSTER = 1
        const val UPDATE_SINGLE_CLUSTER = 2
        const val CALCULATE_CLUSTER = 3
        const val CALCULATE_SINGLE_CLUSTER = 4
    }

    /**
     * Marker  处理类
     *
     * @constructor
     *
     * @param looper
     */
    inner class MarkerHandler(looper: Looper) : Handler(looper) {

        override fun handleMessage(msg: Message) {
            when (msg.what) {
                ADD_CLUSTERS -> {
                    val clusters = msg.obj as List<Cluster>
                    addClustersToMap(clusters)
                }
                ADD_SINGLE_CLUSTER -> {
                    val cluster = msg.obj as Cluster
                    addClusterToMap(cluster)
                }
                UPDATE_SINGLE_CLUSTER -> {
                    val updateCluster = msg.obj as Cluster
                    updateCluster(updateCluster)
                }
            }
        }
    }

    /**
     * Cluster 处理类
     *
     * @constructor
     *
     * @param looper
     */
    inner class ClusterHandler(looper: Looper) : Handler(looper) {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                CALCULATE_CLUSTER -> {
                    calculateClusters()
                }
                CALCULATE_SINGLE_CLUSTER -> {
                    val item = msg.obj as ClusterItem
                    mClusterItems.add(item)
                    calculateSingleCluster(item)
                }
            }
        }
    }

    /**
     * 计算聚合点
     *
     */
    private fun calculateClusters() {
        isCanceled = false
        mClusters.clear()
        //可视范围
        val visibleBounds = aMap.projection.visibleRegion.latLngBounds
        mClusterItems.forEach {clusterItem->
            if (isCanceled) return
            if (clusterItem.carId == carId) {
                val cluster = Cluster(clusterItem.latLng)
                cluster.isSingle = true
                mClusters.add(cluster)
                cluster.addClusterItem(clusterItem)
            } else {
                val latLng = clusterItem.latLng
                if (visibleBounds.contains(latLng)) {
                    var cluster = getCluster(latLng, mClusters)
                    if (cluster == null) {
                        cluster = Cluster(latLng)
                        mClusters.add(cluster)
                    }
                    cluster.addClusterItem(clusterItem)
                }
            }
        }

        //复制一份数据，规避同步
        val clusters: MutableList<Cluster> = ArrayList()
        clusters.addAll(mClusters)
        val message = Message.obtain()
        message.what = ADD_CLUSTERS
        message.obj = clusters
        if (isCanceled) {
            return
        }
        mMarkerHandler?.sendMessage(message)
    }

    /**
     * 计算添加个单个聚合点数据
     *
     * @param item
     */
    private fun calculateSingleCluster(item: ClusterItem) {
        val latLng = item.latLng
        var cluster = getCluster(latLng, mClusters)
        if (cluster != null) {
            cluster.addClusterItem(item)
            updateClusterHandle(cluster)
        } else {
            cluster = Cluster(latLng)
            mClusters.add(cluster)
            cluster.addClusterItem(item)
            addClusterHandle(cluster)
        }
    }

    /**
     * 将聚合元素添加至地图上
     *
     * @param clusters
     */
    private fun addClustersToMap(clusters: List<Cluster>) {
        clearMarkers()
        clusters.forEach {
            addClusterToMap(it)
        }
    }

    /**
     * 添加一个Marker到地图上
     *
     * @param cluster
     */
    private fun addClusterToMap(cluster: Cluster) {
        val latLng = cluster.latLng
        val markerPoint = MarkerOptions().apply {
            if (cluster.clusterCount > 1) {
                anchor(0.5f, 0.5f)
            } else {
                if (isShowSpeed) {
                    anchor(0.01f, 0.5f)
                } else {
                    anchor(0.1f, 0.5f)
                }
            }
            icon(getBitmapDesc(cluster))
            if (!cluster.isSingle && carId.isNotEmpty()) alpha(0.6f)
            position(latLng)
        }
        if (isCanceled) return
        val marker = aMap.addMarker(markerPoint)
        marker.`object` = cluster
        cluster.marker = marker
        mMarkers.add(marker)
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    private fun dp2px(context: Context, dpValue: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (dpValue * scale + 0.5f).toInt()
    }
}
